package game.service.impl;

import cn.hutool.core.lang.Assert;
import com.google.common.collect.Lists;
import common.model.po.GBuilding;
import common.model.po.GRecipe;
import common.model.po.GRecipeBuilding;
import common.model.po.GRecipeItem;
import common.service.CommonGRecipeBuildingService;
import common.util.BigFractionUtil;
import common.util.Constants;
import game.model.dto.RecipeItemDto;
import game.model.request.LoadOneStepRequest;
import game.model.vo.LoadOneStepVo;
import game.model.vo.MaterialVo;
import game.model.vo.ProductVo;
import game.service.GBuildingService;
import game.service.GProductLineService;
import game.service.GRecipeItemService;
import game.service.GRecipeService;
import org.apache.commons.math3.fraction.BigFraction;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 米泽鹏
 * @since 2022-3-2 下午 5:19
 */
@Service
public class GProductLineServiceImpl implements GProductLineService {

	@Resource
	private GRecipeService recipeService;
	@Resource
	private GRecipeItemService recipeItemService;
	@Resource
	private CommonGRecipeBuildingService recipeBuildingService;
	@Resource
	private GBuildingService buildingService;

	@Override
	public List<LoadOneStepVo> loadOneStep(LoadOneStepRequest request) {
		List<LoadOneStepVo> responseList = Lists.newArrayList();
		// 查询所有可以生产该物品的配方搭配
		List<GRecipeItem> recipeProductList = recipeItemService.lambdaQuery().eq(GRecipeItem::getType, 1).eq(GRecipeItem::getProductType, 1).eq(GRecipeItem::getItemId, request.getItemId()).list();
		List<Long> recipeIdList = recipeProductList.stream().map(GRecipeItem::getRecipeId).collect(Collectors.toList());
		if (recipeIdList.isEmpty()) {
			return responseList;
		}
		List<GRecipe> recipeList = recipeService.lambdaQuery().in(GRecipe::getId, recipeIdList).orderByAsc(GRecipe::getSort).list();
		for (GRecipe recipe : recipeList) {
			LoadOneStepVo response = new LoadOneStepVo();
			// 配方id
			response.setRecipeId(recipe.getId());
			response.setRecipeName(recipe.getRecipeName());
			// 配方名称
			int index = recipeList.indexOf(recipe);
			response.setRecipeNameDisplayed(recipe.getRecipeName() + "（" + (index == 0 ? "标准配方" : "替代配方" + index) + "）");
			// 查询该配方的原料和产物信息
			List<RecipeItemDto> recipeItemDtoList = recipeItemService.getAllRecipeItemInfoByRecipeId(recipe.getId());
			List<RecipeItemDto> materialInfoList = recipeItemDtoList.stream().filter(dto -> dto.getType() == 0).collect(Collectors.toList());
			List<RecipeItemDto> productInfoList = recipeItemDtoList.stream().filter(dto -> dto.getType() == 1).collect(Collectors.toList());
			// 计算需求倍数，同时也是建筑数量
			BigFraction quantityPerMinuteNeed = request.getQuantityPerMinuteExactFraction().toBigFraction();
			List<RecipeItemDto> recipeItemCollect = productInfoList.stream().filter(item -> item.getItemId().equals(request.getItemId())).collect(Collectors.toList());
			Assert.isTrue(recipeItemCollect.size() == 1, "未知异常：无法匹配需求物品");
			BigFraction quantityPerMinuteProvide = BigFractionUtil.valueOf(recipeItemCollect.get(0).getQuantityPerMinute());
			BigFraction multipleFraction = quantityPerMinuteNeed.divide(quantityPerMinuteProvide);
			// 原料
			for (RecipeItemDto dto : materialInfoList) {
				MaterialVo material = new MaterialVo();
				material.setItemId(dto.getItemId());
				material.setItemName(dto.getItemName());
				material.setQuantityPerProduction(dto.getQuantityPerProduction());
				BigFraction quantityPerMinuteExactFraction = BigFractionUtil.valueOf(dto.getQuantityPerMinute()).multiply(multipleFraction);
				material.setQuantityPerMinute(quantityPerMinuteExactFraction.bigDecimalValue(2, BigDecimal.ROUND_HALF_UP));
				material.setQuantityPerMinuteExactFraction(BigFractionUtil.toFraction(quantityPerMinuteExactFraction));
				material.setImage(dto.getImage());
				material.setFluid(dto.getFluid());
				response.getMaterialList().add(material);
			}
			// 产物
			for (RecipeItemDto dto : productInfoList) {
				ProductVo productVo = new ProductVo();
				productVo.setItemId(dto.getItemId());
				productVo.setItemName(dto.getItemName());
				productVo.setQuantityPerProduction(dto.getQuantityPerProduction());
				BigFraction quantityPerMinuteExactFraction = BigFractionUtil.valueOf(dto.getQuantityPerMinute()).multiply(multipleFraction);
				productVo.setQuantityPerMinute(quantityPerMinuteExactFraction.bigDecimalValue(2, BigDecimal.ROUND_HALF_UP));
				productVo.setQuantityPerMinuteExactFraction(BigFractionUtil.toFraction(quantityPerMinuteExactFraction));
				productVo.setImage(dto.getImage());
				productVo.setFluid(dto.getFluid());
				// 所有产物
				response.getProductList().add(productVo);
				// 区分主产物和副产物
				if (dto.getItemId().equals(request.getItemId())) {
					response.setMainProduct(productVo);
				} else {
					response.getByProductList().add(productVo);
				}
			}
			// 建筑
			List<GRecipeBuilding> recipeBuildingList = recipeBuildingService.lambdaQuery().eq(GRecipeBuilding::getRecipeId, recipe.getId()).list();
			List<Long> buildingIdList = recipeBuildingList.stream().map(GRecipeBuilding::getBuildingId).collect(Collectors.toList());
			List<GBuilding> buildingList = buildingService.listByIds(buildingIdList);
			// 自动化产线建筑
			List<GBuilding> buildingCollect = buildingList.stream().filter(building -> !Constants.HANDMADE_BUILDING_NAMES.contains(building.getBuildingName())).collect(Collectors.toList());
			Assert.isTrue(buildingCollect.size() <= 1, "未知异常：建筑物种类大于1");
			if (buildingCollect.size() == 1) {
				LoadOneStepVo.LoadOneStepBuildingVo loadOneStepBuildingVo = new LoadOneStepVo.LoadOneStepBuildingVo();
				loadOneStepBuildingVo.setBuildingId(buildingCollect.get(0).getId());
				loadOneStepBuildingVo.setBuildingName(buildingCollect.get(0).getBuildingName());
				loadOneStepBuildingVo.setNeedPower(buildingCollect.get(0).getNeedPower());
				loadOneStepBuildingVo.setOverclockable(buildingCollect.get(0).getOverclockable());
				loadOneStepBuildingVo.setImage(buildingCollect.get(0).getImage());
				loadOneStepBuildingVo.setCountExact(multipleFraction.bigDecimalValue(2, BigDecimal.ROUND_HALF_UP));
				loadOneStepBuildingVo.setCountExactFraction(BigFractionUtil.toFraction(multipleFraction));
				loadOneStepBuildingVo.setCount(multipleFraction.bigDecimalValue(0, BigDecimal.ROUND_UP).intValue());
				loadOneStepBuildingVo.setPower(buildingCollect.get(0).getPower().multiply(BigDecimal.valueOf(loadOneStepBuildingVo.getCount())));
				response.setBuildingVo(loadOneStepBuildingVo);
			}
			// 手搓建筑
			List<GBuilding> handmadeBuildings = buildingList.stream().filter(building -> Constants.HANDMADE_BUILDING_NAMES.contains(building.getBuildingName())).collect(Collectors.toList());
			for (GBuilding building : handmadeBuildings) {
				LoadOneStepVo.LoadOneStepBuildingVo loadOneStepBuildingVo = new LoadOneStepVo.LoadOneStepBuildingVo();
				loadOneStepBuildingVo.setBuildingId(building.getId());
				loadOneStepBuildingVo.setBuildingName(building.getBuildingName());
				loadOneStepBuildingVo.setNeedPower(building.getNeedPower());
				loadOneStepBuildingVo.setOverclockable(building.getOverclockable());
				loadOneStepBuildingVo.setImage(building.getImage());
				response.getHandmadeBuildingVoList().add(loadOneStepBuildingVo);
			}
			responseList.add(response);
		}
		return responseList;
	}

}
